package io.renren.modules.practice.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.utils.ShiroUtils;
import io.renren.modules.practice.dao.AlgorithmQuizDao;
import io.renren.modules.practice.dao.AlgorithmTestCaseDao;
import io.renren.modules.practice.dao.StudentAlgorithmSubmitDao;
import io.renren.modules.practice.dao.UserCodeSaveDao;
import io.renren.modules.practice.entity.*;
import io.renren.modules.practice.entity.dto.AlgorithmSubmitDto;
import io.renren.modules.practice.entity.dto.CodeSaveDto;
import io.renren.modules.practice.entity.vo.AlgorithmQuizDetailVo;
import io.renren.modules.practice.entity.vo.AlgorithmSubmitResultVo;
import io.renren.modules.practice.entity.vo.TestCaseResultVo;
import io.renren.modules.practice.entity.vo.TestCaseVo;
import io.renren.modules.practice.service.AlgorithmPracticeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.renren.modules.learn.dao.AlgorithmChapterDao;
import io.renren.modules.learn.entity.AlgorithmChapterEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class AlgorithmPracticeServiceImpl extends ServiceImpl<AlgorithmQuizDao, AlgorithmQuizEntity> implements AlgorithmPracticeService {

    @Autowired
    private AlgorithmTestCaseDao algorithmTestCaseDao;

    @Autowired
    private StudentAlgorithmSubmitDao studentAlgorithmSubmitDao;

    @Autowired
    private UserCodeSaveDao userCodeSaveDao;

    @Autowired
    private AlgorithmChapterDao algorithmChapterDao;

    @Override
    public List<AlgorithmQuizEntity> getQuizListByChapterId(Integer chapterId) {
        return baseMapper.selectByChapterId(chapterId);
    }

    @Override
    public AlgorithmQuizDetailVo getQuizDetailById(Integer quizId) {
        // 查询题目信息
        AlgorithmQuizEntity quiz = baseMapper.selectById(quizId);
        if (quiz == null) {
            return null;
        }

        // 查询测试用例
        List<AlgorithmTestCaseEntity> testCases = algorithmTestCaseDao.selectByQuizId(quizId);
        List<TestCaseVo> testCaseVos = testCases.stream().map(testCase -> {
            TestCaseVo vo = new TestCaseVo();
            BeanUtils.copyProperties(testCase, vo);
            return vo;
        }).collect(Collectors.toList());

        // 组装返回结果
        AlgorithmQuizDetailVo detailVo = new AlgorithmQuizDetailVo();
        BeanUtils.copyProperties(quiz, detailVo);
        detailVo.setTestCases(testCaseVos);

        return detailVo;
    }

    @Override
    public AlgorithmSubmitResultVo submitAlgorithmCode(AlgorithmSubmitDto submitDto) {
        AlgorithmSubmitResultVo result = new AlgorithmSubmitResultVo();
        try {
            // 获取题目信息和测试用例
            AlgorithmQuizEntity quiz = baseMapper.selectById(submitDto.getQuizId());
            List<AlgorithmTestCaseEntity> testCases = algorithmTestCaseDao.selectByQuizId(submitDto.getQuizId());
            if (quiz == null || testCases.isEmpty()) {
                result.setStatus(3); // 运行错误
                result.setErrorMessage("题目不存在或测试用例为空");
                return result;
            }
            // 提取函数名
            String userCode = submitDto.getCode();
            Pattern p = Pattern.compile("def\\s+(\\w+)\\s*\\(");
            Matcher m = p.matcher(userCode);
            String funcName = null;
            if (m.find()) {
                funcName = m.group(1);
            }
            // 执行测试用例（全部用本地python3进程）
            List<TestCaseResultVo> testCaseResults = new ArrayList<>();
            int passedCases = 0;
            long totalExecutionTime = 0;
            for (AlgorithmTestCaseEntity testCase : testCases) {
                TestCaseResultVo testCaseResult = new TestCaseResultVo();
                testCaseResult.setTestCaseId(testCase.getId());
                testCaseResult.setInputData(testCase.getInputData());
                testCaseResult.setExpectedOutput(testCase.getExpectedOutput());
                File temp = null;
                try {
                    long startTime = System.currentTimeMillis();
                    // 自动补全调用代码
                    String codeToRun = userCode;
                    if (funcName != null) {
                        codeToRun += "\nprint(" + funcName + "(" + testCase.getInputData() + "))";
                    }
                    String actualOutput = "";
                    if ("python2".equals(submitDto.getPythonVersion())) {
                        // Jython捕获print输出
                        javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager();
                        javax.script.ScriptEngine engine = manager.getEngineByName("python");
                        if (engine == null) throw new RuntimeException("Python2环境不可用");
                        StringBuilder py = new StringBuilder();
                        py.append("import sys\n");
                        py.append("from java.io import ByteArrayOutputStream, PrintStream\n");
                        py.append("out = ByteArrayOutputStream()\n");
                        py.append("sys.stdout = PrintStream(out)\n");
                        py.append(codeToRun).append("\n");
                        py.append("sys.stdout.flush()\n");
                        py.append("result = out.toString()\n");
                        engine.eval(py.toString());
                        Object captured = engine.get("result");
                        actualOutput = captured != null ? captured.toString().trim() : "";
                    } else {
                        // python3本地进程
                        temp = File.createTempFile("user_code", ".py");
                        try (Writer writer = new OutputStreamWriter(new FileOutputStream(temp), StandardCharsets.UTF_8)) {
                            writer.write(codeToRun);
                        }
                        ProcessBuilder pb = new ProcessBuilder("D:/python/python.exe", temp.getAbsolutePath());
                        pb.redirectErrorStream(true);
                        Process process = pb.start();
                        StringBuilder output = new StringBuilder();
                        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                            String line;
                            while ((line = reader.readLine()) != null) {
                                output.append(line).append("\n");
                            }
                        }
                        process.waitFor();
                        actualOutput = output.toString().trim();
                    }
                    long executionTime = System.currentTimeMillis() - startTime;
                    totalExecutionTime += executionTime;
                    testCaseResult.setActualOutput(actualOutput);
                    testCaseResult.setExecutionTime((int) executionTime);
                    boolean passed = compareOutput(actualOutput, testCase.getExpectedOutput());
                    testCaseResult.setPassed(passed);
                    if (passed) {
                        passedCases++;
                    }
                } catch (Exception e) {
                    testCaseResult.setPassed(false);
                    testCaseResult.setErrorMessage("执行错误: " + e.getMessage());
                    log.error("代码执行错误: {}", e.getMessage());
                } finally {
                    if (temp != null && temp.exists()) temp.delete();
                }
                testCaseResults.add(testCaseResult);
            }
            // 设置结果
            result.setPassedCases(passedCases);
            result.setTotalCases(testCases.size());
            result.setExecutionTime((int) totalExecutionTime);
            result.setTestCaseResults(testCaseResults);
            if (passedCases == testCases.size()) {
                result.setStatus(1); // 通过
                result.setScore(100);
            } else {
                result.setStatus(4); // 答案错误
                result.setScore((int) (passedCases * 100.0 / testCases.size()));
            }
            // 保存提交记录
            saveSubmitRecord(submitDto, result);
        } catch (Exception e) {
            log.error("算法题目判题异常: {}", e.getMessage(), e);
            result.setStatus(3); // 运行错误
            result.setErrorMessage("系统错误: " + e.getMessage());
        }
        return result;
    }

    @Override
    public void saveUserCode(CodeSaveDto codeSaveDto) {
        UserCodeSaveEntity saveEntity = new UserCodeSaveEntity();
        saveEntity.setUserId(ShiroUtils.getUserId().intValue());
        saveEntity.setQuizId(codeSaveDto.getQuizId());
        saveEntity.setCodeName(codeSaveDto.getCodeName());
        saveEntity.setCodeContent(codeSaveDto.getCodeContent());
        saveEntity.setLanguage(codeSaveDto.getLanguage());
        saveEntity.setSaveTime(new Date());
        saveEntity.setUpdateTime(new Date());
        
        userCodeSaveDao.insert(saveEntity);
    }

    @Override
    public List<CodeSaveDto> getUserSavedCodes(Integer userId, Integer quizId) {
        List<UserCodeSaveEntity> savedCodes = userCodeSaveDao.selectByUserIdAndQuizId(userId, quizId);
        return savedCodes.stream().map(entity -> {
            CodeSaveDto dto = new CodeSaveDto();
            dto.setQuizId(entity.getQuizId());
            dto.setCodeName(entity.getCodeName());
            dto.setCodeContent(entity.getCodeContent());
            dto.setLanguage(entity.getLanguage());
            return dto;
        }).collect(Collectors.toList());
    }

    /**
     * 构建测试代码
     */
    private String buildTestCode(String userCode, String functionName, String inputData) {
        // 这里需要根据具体的函数签名和输入数据格式来构建测试代码
        // 简化版本，实际应用中需要更复杂的处理
        return userCode + "\n" + 
               "result = " + functionName + "(" + inputData + ")\n" +
               "print(result)";
    }

    /**
     * 比较输出结果
     */
    private boolean compareOutput(String actual, String expected) {
        if (actual == null && expected == null) {
            return true;
        }
        if (actual == null || expected == null) {
            return false;
        }
        return actual.trim().equals(expected.trim());
    }

    /**
     * 保存提交记录
     */
    private void saveSubmitRecord(AlgorithmSubmitDto submitDto, AlgorithmSubmitResultVo result) {
        StudentAlgorithmSubmitEntity submitEntity = new StudentAlgorithmSubmitEntity();
        submitEntity.setUserId(ShiroUtils.getUserId().intValue());
        submitEntity.setQuizId(submitDto.getQuizId());
        submitEntity.setCode(submitDto.getCode());
        submitEntity.setLanguage(submitDto.getLanguage());
        submitEntity.setStatus(result.getStatus());
        submitEntity.setErrorMessage(result.getErrorMessage());
        submitEntity.setExecutionTime(result.getExecutionTime());
        submitEntity.setPassedCases(result.getPassedCases());
        submitEntity.setTotalCases(result.getTotalCases());
        submitEntity.setScore(result.getScore());
        submitEntity.setSubmitTime(new Date());
        
        studentAlgorithmSubmitDao.insert(submitEntity);
    }

    @Override
    public List<AlgorithmChapterEntity> getChapters() {
        return algorithmChapterDao.getAllChapters();
    }

    @Override
    public String runPythonCode(String code, String pythonVersion) {
        log.info("runPythonCode called, version={}, code=\n{}", pythonVersion, code);
        String result = "";
        String codeToRun = code;
        // 自动补全调用代码：如果只定义了函数且无调用，则自动加print调用
        Pattern p = Pattern.compile("def\\s+(\\w+)\\s*\\(");
        Matcher m = p.matcher(code);
        if (m.find()) {
            String funcName = m.group(1);
            // 检查是否已调用
            if (!code.matches("(?s).*" + funcName + "\\s*\\(.*")) {
                codeToRun += "\nprint(" + funcName + "([3,1,2]))";
            }
        }
        if ("python2".equals(pythonVersion)) {
            // 用Jython并捕获print输出
            try {
                javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager();
                javax.script.ScriptEngine engine = manager.getEngineByName("python");
                if (engine == null) return "Python2环境不可用";
                // 注入捕获stdout的代码
                StringBuilder py = new StringBuilder();
                py.append("import sys\n");
                py.append("from java.io import ByteArrayOutputStream, PrintStream\n");
                py.append("out = ByteArrayOutputStream()\n");
                py.append("sys.stdout = PrintStream(out)\n");
                py.append(codeToRun).append("\n");
                py.append("sys.stdout.flush()\n");
                py.append("result = out.toString()\n");
                engine.eval(py.toString());
                Object captured = engine.get("result");
                result = captured != null ? captured.toString() : "";
            } catch (Exception e) {
                result = "Python2运行异常: " + e.getMessage();
            }
        } else if ("python3".equals(pythonVersion)) {
            // 用本地python3
            File temp = null;
            try {
                temp = File.createTempFile("user_code", ".py");
                try (Writer writer = new OutputStreamWriter(new FileOutputStream(temp), StandardCharsets.UTF_8)) {
                    writer.write(codeToRun);
                }
                ProcessBuilder pb = new ProcessBuilder("D:/python/python.exe", temp.getAbsolutePath());
                pb.redirectErrorStream(true);
                Process process = pb.start();
                StringBuilder output = new StringBuilder();
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        output.append(line).append("\n");
                    }
                }
                process.waitFor();
                result = output.toString();
            } catch (Exception e) {
                result = "Python3运行异常: " + e.getMessage();
            } finally {
                if (temp != null && temp.exists()) temp.delete();
            }
        } else {
            result = "不支持的版本";
        }
        log.info("runPythonCode result=\n{}", result);
        return result;
    }
} 